﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SqlExecuter.Client.Model;
using System.IO;
using System.Collections.ObjectModel;
using System.Windows.Input;
using SqlExecuter.Client.Commands;
using System.Windows;

namespace SqlExecuter.Client.ViewModel
{
    public class MainViewModel : ViewModelBase
    {
        #region Member Variables
        private bool _SyncValue;
        private string _RootDirectoryPath;
        private FsDirectory _RootDirectory;
        private string _FilesContent;
        private ObservableCollection<FileSystemItem> _SelectedItems;
        private ObservableCollection<string> _RecentPaths;

        #endregion

        #region Properties and Commands
        public string RootDirectoryPath
        {
            get { return _RootDirectoryPath; }
            set
            {
                if (value == _RootDirectoryPath) return;
                _RootDirectoryPath = value;
                OnPropertyChanged("RootDirectoryPath");
                if (!RecentPaths.Contains(RootDirectoryPath))
                {
                    RecentPaths.Insert(0, RootDirectoryPath); //Add at the beginning
                    SettingsManager.UpdateRecentLocations(RecentPaths);
                }
                RootDirectory = new FsDirectory(new DirectoryInfo(value));
            }
        }

        public FsDirectory RootDirectory
        {
            get { return _RootDirectory; }
            set
            {
                if (value == _RootDirectory) return;

                //Before assignging the new value to the directory, detach the events to avoid memory leaks
                if (_RootDirectory != null)
                    AttachIsSelectedEvents(_RootDirectory, false);
                _RootDirectory = value;
                OnPropertyChanged("RootDirectory");
                AttachIsSelectedEvents(_RootDirectory, true);
            }

        }

        public string FilesContent
        {
            get { return _FilesContent; }
            set
            {
                if (_FilesContent == value)
                    return;
                _FilesContent = value;
                OnPropertyChanged("FilesContent");
            }
        }

        public ObservableCollection<FileSystemItem> SelectedItems
        {
            get { return _SelectedItems; }
            set
            {
                _SelectedItems = value;
                OnPropertyChanged("SelectedItems");
            }
        }

        public int SelectedItemsCount
        {
            get { return SelectedItems.Count; }
        }

        public ObservableCollection<string> RecentPaths
        {
            get { return _RecentPaths; }
            set { _RecentPaths = value; }
        }

        #region Commands
        public DelegateCommand Populate { get; set; }
        public DelegateCommand DisplayContent { get; set; }
        public DelegateCommand Copy { get; set; }
        public DelegateCommand SelectAllFiles { get; set; }
        #endregion
        #endregion
        public MainViewModel()
        {
            Initialize();

            Populate = new DelegateCommand(PopulateDirectory, CanPopulateDirectory);
            DisplayContent = new DelegateCommand(DisplayContentExecute, CanDisplayContent);
            Copy = new DelegateCommand(CopyExecute, CanCopy);
            SelectAllFiles = new DelegateCommand(SelectAllFilesExecute, CanSelectAllFiles);
        }


        private void Initialize()
        {
            FilesContent = string.Empty;
            SelectedItems = new ObservableCollection<FileSystemItem>();
            SelectedItems.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(SelectedItems_CollectionChanged);

            if (!string.IsNullOrWhiteSpace(RootDirectoryPath))
                RootDirectory = new FsDirectory(new DirectoryInfo(RootDirectoryPath));
            else
                RootDirectory = new FsDirectory();

            RecentPaths = new ObservableCollection<string>();
            try
            {
                SettingsManager.GetRecentLocations().ToList().ForEach(s => RecentPaths.Add(s));
            }
            catch (Exception)
            {
                //There might be an exception, reading the settings file, or it might not be present.
            }
        }

        private void AttachIsSelectedEvents(FsDirectory directory, bool attach)
        {
            if (attach)
                directory.Files.ForEach(f => f.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(FileSystemItem_PropertyChanged));
            else
                directory.Files.ForEach(f => f.PropertyChanged -= new System.ComponentModel.PropertyChangedEventHandler(FileSystemItem_PropertyChanged));
            directory.SubDirectories.ForEach(d => AttachIsSelectedEvents(d, attach));

        }

        void FileSystemItem_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            if (_SyncValue) return;
            if (e.PropertyName != "IsSelected") return;
            if (sender is FsFile)
            {
                FsFile file = (FsFile)sender;
                if (file.IsSelected)
                    SelectedItems.Add(file);
                else
                    SelectedItems.Remove(file);
            }
        }

        void SelectedItems_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            OnPropertyChanged("SelectedItemsCount");
        }

        private bool IsCtrlPressed
        {
            get
            {
                return Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl);
            }
        }


        public void SelectedItemChanged(FileSystemItem item)
        {
            if (item is FsDirectory) return;
            if (!IsCtrlPressed)
            {
                _SyncValue = true;
                SelectedItems.AsParallel().ForAll(f => f.IsSelected = false);
                SelectedItems.Clear();
                _SyncValue = false;
            }
            FsFile file = item as FsFile;
            file.IsSelected = true;
        }

        private void CopyExecute()
        {
            try { Clipboard.SetText(FilesContent); }
            catch (Exception ex) { }
        }

        public bool CanCopy()
        {
            return FilesContent.Length > 0;
        }

        public void PopulateDirectory()
        {
            RootDirectory = new FsDirectory(new DirectoryInfo(RootDirectoryPath));
        }

        private bool CanPopulateDirectory()
        {
            return !string.IsNullOrWhiteSpace(RootDirectoryPath);
        }

        private void DisplayContentExecute()
        {
            StringBuilder sb = new StringBuilder();

            foreach (FsFile file in SelectedItems)
            {
                if (file == null) continue;
                using (StreamReader reader = new StreamReader(file.FullPath))
                {
                    sb.AppendLine(reader.ReadToEnd());
                    //Add two extra lines
                    sb.AppendLine();
                    sb.AppendLine();
                }
            }
            FilesContent = sb.ToString();

        }

        private bool CanDisplayContent()
        {
            return SelectedItems.Count > 0;
        }

        public void SelectAllFilesExecute()
        {
            _SyncValue = true;
            SelectFiles(RootDirectory);
            _SyncValue = false;
        }

        public void SelectFiles(FsDirectory rootdirectory)
        {
            if (rootdirectory.DirectoriesAndFiles.Count > 0)
            {
                rootdirectory.Files.AsParallel().ForAll(f => f.IsSelected = true);
                rootdirectory.Files.AsParallel().ForAll(f => SelectedItems.Add(f));
                rootdirectory.SubDirectories.ForEach(d => SelectFiles(d));
            }
        }

        public bool CanSelectAllFiles()
        {
            return RootDirectory.DirectoriesAndFiles.Count > 0;
        }
    }
}
